package com.hqyj.cloudAccount.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hqyj.cloudAccount.service.UserService;
import com.hqyj.cloudAccount.service.toTestOpenFeign;
import com.hqyj.entity.account.User;
import com.hqyj.entity.account.UserRole;
import com.hqyj.entity.account.vo.UserVo;
import com.hqyj.entity.common.vo.Result;
import com.hqyj.entity.common.vo.Search;
import com.hqyj.entity.Test.City;
import com.hqyj.cloudAccount.dao.UserDao;
import com.hqyj.cloudAccount.dao.UserRoleDao;
import com.hqyj.cloudAccount.utils.MD5Util;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.vavr.control.Try;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * @Description: User Service Impl
 * @author: HymanHu
 * @date: 2021年2月21日
 */
@Service
public class UserServiceImpl implements UserService {
    public final static Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserDao userDao;
    @Autowired
    private UserRoleDao userRoleDao;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private toTestOpenFeign toTestOpenFeign;

    @Override
    public User getUserByUserNameAndPassword(String userName, String password) {
        return userDao.getUserByUserNameAndPassword(userName, MD5Util.getMD5(password));
    }

    @Override
    public User getUserByUserName(String userName) {
        List<User> users = Optional
                .ofNullable(userDao.getUserByUserName(userName))
                .orElse(Collections.emptyList());
        return users.isEmpty() ? null : users.get(0);
    }

    @Override
    public Result<User> login(User user) {
        User temp = userDao.getUserByUserNameAndPassword(
                user.getUserName(), MD5Util.getMD5(user.getPassword()));
        if (temp != null) {
            return new Result<User>(Result.ResultStatus.SUCCESS.code, "登录成功");
        } else {
            return new Result<User>(Result.ResultStatus.FAILED.code, "用户名或密码错误");
        }
    }

    @Override
    public void logout() {
        return;
    }

    @Override
    @Transactional
    public Result<User> insertUser(User user) {
        if (StringUtils.isBlank(user.getUserName()) ||
                StringUtils.isBlank(user.getPassword())) {
            return new Result<User>(Result.ResultStatus.FAILED.code,
                    "User Name is null.");
        }

        List<User> users = Optional
                .ofNullable(userDao.getUserByUserName(user.getUserName()))
                .orElse(Collections.emptyList());
        if (users.size() > 0) {
            return new Result<User>(Result.ResultStatus.FAILED.code,
                    "User name repeat.");
        }

        user.setCreateDate(LocalDateTime.now());
        user.setUpdateDate(LocalDateTime.now());
        user.setPassword(MD5Util.getMD5(user.getPassword()));
        userDao.insertUser(user);
        if (user.getRoles() != null) {
            user.getRoles().stream()
                    .forEach(item -> {
                        userRoleDao.insertUserRole(
                                new UserRole(user.getId(), item.getId()));
                    });
        }
        return new Result<User>(
                Result.ResultStatus.SUCCESS.code, "Insert success", user);
    }

    @Override
    @Transactional
    public Result<User> updateUser(User user) {
        List<User> users = Optional
                .ofNullable(userDao.getUserByUserName(user.getUserName()))
                .orElse(Collections.emptyList());
        if (users.stream().filter(item -> item.getId() != user.getId()).count() > 0) {
            return new Result<User>(Result.ResultStatus.FAILED.code,
                    "User Name or email is repeat.");
        }

        userDao.updateUser(user);
        if (user.getRoles() != null && !user.getRoles().isEmpty()) {
            userRoleDao.deleteUserRoleByUserId(user.getId());
            user.getRoles().stream()
                    .forEach(item -> {
                        userRoleDao.insertUserRole(
                                new UserRole(user.getId(), item.getId()));
                    });
        }

        return new Result<User>(Result.ResultStatus.SUCCESS.code,
                "Update success", user);
    }

    @Override
    public User getUserById(int id) {
        return userDao.getUserById(id);
    }

    @Override
    @Transactional
    public Result<Object> deleteUserById(int id) {
        userDao.deleteUserById(id);
        userRoleDao.deleteUserRoleByUserId(id);
        return new Result<>(Result.ResultStatus.SUCCESS.code, "Delete success");
    }

    @Override
    public PageInfo<User> getUsersBySearchBean(Search search) {
        search.init();
        PageHelper.startPage(search.getCurrentPage(), search.getPageSize());
        return new PageInfo<>(Optional
                .ofNullable(userDao.getUsersBySearchVo(search))
                .orElse(Collections.emptyList()));
    }

    @Override
    public Result<UserVo> getUserVoById(int userId, int cityId) {
        UserVo userVo = new UserVo();
        User user = userDao.getUserById(userId);
        if (user == null) {
            return new Result<>(Result.ResultStatus.FAILED.code, "find wrong");
        }
        BeanUtils.copyProperties(user, userVo);//将user拷贝到userVo中


//        City city = restTemplate.getForObject(
//                "http://spring-cloud-test//api/test/city/{cityId}",
//                City.class,
//                cityId
//        );

        CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
                .failureRateThreshold(50)
                .waitDurationInOpenState(Duration.ofMillis(1000))
                .build();
        CircuitBreaker circuitBreaker = CircuitBreaker.of("circuitBreakerPloy", circuitBreakerConfig);
        Try<City> circuitBreakerSupplier = Try.ofSupplier(CircuitBreaker.decorateSupplier(
                circuitBreaker,
//				() -> restTemplate.getForObject(
//						"http://spring-cloud-test/api/test/city/{cityId}",
//						City.class,
//						cityId)
                () -> toTestOpenFeign.selectCity(cityId)
        )).recover(Exception.class, new City());


        userVo.setCity(circuitBreakerSupplier.get());


        return new Result<>(Result.ResultStatus.SUCCESS.code, "success", userVo);



        /*
         * getForObject 只返回内容
         * getForEntity 返回头 尾 内容
         * */
    }
}
